package edu.asu.sapa.ground.update;

import edu.asu.sapa.Planner;
import edu.asu.sapa.ground.MathForm;
import edu.asu.sapa.ground.Operator;
import edu.asu.sapa.ground.Problem;
import edu.asu.sapa.ground.PropDB;
import edu.asu.sapa.ground.Proposition;
import edu.asu.sapa.ground.State;
import edu.asu.sapa.heuristic.PG;

public class Assign extends Update {

	public Proposition p;
	public int id;
	public boolean value;

	public boolean isConstant = false;

	public Assign(Proposition p, int id, boolean value) {
		this.p = p;
		this.id = id;
		this.value = value;
	}

	public Assign(Assign effect) {
		p = effect.p;
		id = effect.id;
		value = effect.value;
		isConstant = effect.isConstant;
	}

	public void relaxedUpdate(PG pg, State s, Context c, float time) {
		if (value)
			pg.addPendingProposition(p,time+Planner.EPSILON,0,0);
	}
	public void relaxedStart(PG pg, State s, Context c, float time) {
		if (value)
			pg.addPendingProposition(p,time+Planner.EPSILON,0,0);
	}
	public void relaxedFinish(PG pg, State s, Context c, float time) {
	}
	
	public boolean updateBefore(State s, Context c, float time) {
		PropDB db = s.propDB;
		return db.setAtInstant(id, value, time);
	}
	
	public boolean updateAfter(State s, Context c, float time) {
		return false;
	}
	
	public boolean startBefore(State s, Context c, float time) {
		PropDB db = s.propDB;
		return db.setAt(id, value, time);
	}
	
	public boolean startAfter(State s, Context c, float time) {
		PropDB db = s.propDB;
		return db.setAfter(id, value, time);
	}
	
	public boolean finishBefore(State s,Context c, float time) {
		return s.propDB.unlock(id,time);
	}
	
	public boolean finishAfter(State s,Context c, float time) {
		return s.propDB.unlock(id,time);
	}
	
	public boolean applicableBefore(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		return db.writableAt(id,time);
	}
	public boolean applicableAfter(State s, Context c) {
		PropDB db = s.propDB;
		float time = s.time;
		return db.writableAfter(id,time);
	}

	public int compareTo(Assign o) {
		//assert this != null && o != null;
		if (id < o.id)
			return -1;
		if (id > o.id)
			return 1;
		if (value != o.value)
			if (!value)
				return -1;
			else
				return 1;
		return 0;
	}
	
	public int compareTo(Update u) {
		return compareTo((Assign)u);
	}

	public String toString() {
		return "(:= " + id + " " + value + ")";
	}

	public boolean analyzeStatic(float dur) {
		isConstant = false;

		if (p.isConstant) {
			isConstant = true;
			id = 0;
			p = Problem.propositions.get(0);
			value = (value == p.value);
			assert value == true;
			return value == true;
		}
		return true;
	}
	
	@Override
	public boolean isFail() {
		return isConstant && !value;
	}
	
	@Override
	public boolean isNoOp() {
		return isConstant && value;
	}
	
	@Override
	public void removeDependencies(Operator o) {
		if (value) {
			p.removeAdd(o.id);
			o.removeAdd(id);
		}
		else {
			p.removeDelete(o.id);
			o.removeDelete(id);
		}
	}
	
	public void setDependencies(Operator o) {
		if (value) {
			p.addAdd(o.id);
			o.addAdd(id);
		}
		else {
			p.addDelete(o.id);
			o.addDelete(id);
		}
	}
	
}
